#ifndef CSGSOLIDNODE_H
#define CSGSOLIDNODE_H

#include "csgnode.h"
#include "tree/tree.h"
#include "bezier.h"

class CSGSolidNode : public CSGNode, public Bezier
{
public:
    CSGSolidNode();
    CSGSolidNode(int *_ctrlPoly, double **_ctrlPts, CSGNode *parent = NULL);
    ~CSGSolidNode();

    // draw
    virtual void drawBoundingBox();
    virtual void drawControlPolygon(bool fill = false);
    virtual void drawNaively(bool grid);
    virtual void drawCasteljau();
    virtual void drawDomain(bool grid);

    // compute
    void computeBoundingBox();
    bool solve(StarTestBox *box, double ** patchCtrlPts, int k, double ** curveCtrlPts, double x, double y);
    bool complementSolve(StarTestBox *box, double ** patchCtrlPts, int k, double ** curveCtrlPts, double x, double y);
    void generateSolidPoints();
    void evalPoint(double u, double v, double w, double*pt);
    int getNumOfCtrlPts();

    virtual void setRotation(double _rot);
    virtual void setTranslation(double x, double y = 0);
    virtual void setScale(double x, double y = 1);

    virtual void initial(StarTestBox &box, int dim = 3);

    // test
    virtual bool emptyTest(StarTestBox *box);
    virtual bool starTest(StarTestBox *box, double *pt);
    virtual bool complementStarTest(StarTestBox *box, double *pt);
    virtual bool ptInSet(double *pt);

    void criticalTest(StarTestBox *paramBox);
    bool curveIntersectSegment(int k, double ** curveCtrlPts, double x, double y, StarTestBox * box);
    bool bdAgainstStar(double x, double y, StarTestBox *box, int bound);
    bool bdAgainstComplementStar(double x, double y, StarTestBox *box, int bound);
    bool intersectBoundingBox(StarTestBox *box);
    bool intersectBox(StarTestBox *box);
    bool boxIntersectBoundary(StarTestBox *box);
    bool boxIntersectBoundaryCurve(StarTestBox *box, int bound);
    bool boxContainsCriticalPt(StarTestBox *box);
    bool starCondition(StarTestBox *box, double *pt);
    bool complementStarCondition(StarTestBox *box, double *pt);

    Expression *expSolid(int *dim, double **pt_array,
                          Expression& expr_u, Expression& expr_v, Expression& expr_w);

private:
    // draw
    void drawMesh(int row, int col, double **meshPts, bool bPolygon = false);
    void drawCasteljau(CSGSolidNode& solid, int level);

    void criticalTest(TreeNode<StarTestBox>* node, int M, int N, double **jCtrlPts);
    void releaseCtrlPts();
    void releaseCtrlPts(int m, int n, int d, double **ctrlPts);

    void drawOctahedra(int *dim, double **pts);
    void drawMesh(int *dim, double **pts);
    void drawCube(double **pt);
    void drawRect(double *p1, double *p2, double *p3, double *p4, double *c);

private:
    Bezier orgBezier;
    StarTestBox boundingBox;
    bool critical;

    // naive patch points
    int dimSolidPts[3];
    int numOfSolidPts;
    double **solidPts;

    Tree<StarTestBox> * domainTree;
};

#endif // CSGSOLIDNODE_H
